#include "globals.h"
#include "util.h"
#include "scan.h"

#define MAXLINELEN 256
static int linepos=0;
static int currentLineSize=0; //current buffer string length;
static char lineBuf[MAXLINELEN];//One line each time

char tokenString[MAXTOKENLEN+1];//Used to save the token string

static int EOFFLAG=0;

static struct{
  char *str;
  TokenType word;
}reservedWords[MAXRESERVED]
={{"if",IF},{"then",THEN},{"else",ELSE},{"end",END},{"repeat",REPEAT},
  {"until",UNTIL},{"read",READ},{"write",WRITE}};


typedef enum{
  Start,DONE,INNUM,INID,
  INCOMMENT,INASSIGN
}StateType;//There are six state in DFA. Page 54


/*
static int isalpha(char c){
  if(('a'<=c&&c<='z')||('A'<=c&&c<='Z')){
    return 1;
  }
  return 0;
}
*/
/*
static int isdigit(char c){
  if(c>='0'&&c<='9'){
    return 1;
  }
  return 0;
  }
*/
char getNextChar(){
  if(linepos>=currentLineSize){
    //Pay attention to this
    lineno++;
    if(fgets(lineBuf,MAXLINELEN-1,source)){
      //EOF='\0'
      currentLineSize=strlen(lineBuf);
      linepos=0;
      return lineBuf[linepos++];
    }
    else{
      EOFFLAG=1;
      return EOF;
    }
  }
  else
    return lineBuf[linepos++];
}
TokenType reservedLookup(char *str){
  int i;
  for(i=0;i<8;i++){
    if(strcmp(str,reservedWords[i].str)==0)
      return reservedWords[i].word;
  }
  return ID;
}
void ungetChar(){
  if(EOFFLAG==0)linepos--;
}
TokenType getToken(){
  StateType state=Start;
  int c;
  int save=0;
  int tokenIndex=0;
  TokenType currentToken;

  while(state!=DONE){
    c=getNextChar();
    switch(state){
    case Start:
      if(isalpha(c)){
        save=1;
        state=INID;
      }
      else if(isdigit(c)){
        save=1;
        state=INNUM;
      }
      else if(c=='{'){
        //printf("Incomment\n");
        state=INCOMMENT;
      }
      else if(c==':'){
        save=1;
        state=INASSIGN;
      }
      else if(c==' '||c=='\r'||c=='\n'){
        state=Start;
      }
      else{
        state=DONE;
        save=1;
        switch(c){
        case EOF:currentToken=ENDFILE;break;
        case '+':currentToken=PLUS;break;
        case '-':currentToken=MINUS;break;
        case '*':currentToken=MUL;break;
        case '/':currentToken=DIV;break;
        case '=':currentToken=EQUAL;break;
        case '<':currentToken=LESS;break;
        case '(':currentToken=LBRACKET;break;
        case ')':currentToken=RBRACKET;break;
        case ';':currentToken=SEMI;break;
        default: ;
        }
      }
      break;
    case INID:
      save=1;
      if(!isalpha(c)){
        ungetChar(c);
        state=DONE;
        save=0;
        currentToken=ID;
      }
      break;
    case INNUM:
      save=1;
      if(!isdigit(c)){
        ungetChar(c);
        state=DONE;
        save=0;
        currentToken=NUM;
      }
      break;
    case INCOMMENT:
      if(c=='}'){
        state=Start;
        //printf("Out of comment\n");
      }
      break;
    case INASSIGN:
      if(c=='='){
        save=1;
        state=DONE;
        currentToken=ASSIGN;
      }
      else{
        printf("error3\n");
      }
      break;
    case DONE:
      /*
        It should never be here!
       */
      break;

    default:;
    }
    if(save==1&&(tokenIndex<MAXTOKENLEN)){
      //printf("InSave\n");
      tokenString[tokenIndex++]=c;
    }
    if(state==DONE){
      //printf("InDone\n");
      tokenString[tokenIndex]='\0';
      if(tokenString[0]!='\0'&&currentToken!=ENDFILE)
        printf("%s\n",tokenString);
      if(currentToken==ID){
        currentToken=reservedLookup(tokenString);
      }
      //return TokenType;
    }
    
  }

  return currentToken;
}
